package com.spring.aop;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * 负责动态创建代理对象
 */
public class CglibProxyCreator implements MethodInterceptor {
	// 持有原始对象的引用
	private Object targetObject;
	
	// 拦截器链 map
	private Map<Method, InterceptorChain> interceptorMap;
	
	
	/**
	 * 创建代理对象
	 */
	public Object getInstance(Object targetObject, Map<Method, InterceptorChain> interceptorMap) {
		this.interceptorMap = interceptorMap;
		this.targetObject = targetObject;
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(targetObject.getClass());
		enhancer.setCallback(this);
		return enhancer.create();
	}
	
	
	@Override
	public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		// 过滤掉 toString()  hashCode 之类的方法，直接用自己执行即可
		if (method.getDeclaringClass() == Object.class) {
			return method.invoke(this, args);
		}
		
		//  查找这个方法有没有相关的拦截器链
		InterceptorChain chain = interceptorMap.get(method);
		if (chain == null) {
			// 没有拦截器链 直接运行目标方法即可
			return method.invoke(targetObject, args);
		}
		
		// 有拦截器链，则把参数传入拦截器，执行拦截器处理方法
		
		try{
			AopContext.setCurrentProxy(this);
			
			return chain.proceed(targetObject, method, args);
		}finally {
			AopContext.clear();
		}
	}
	
	/**
	 * 经过检查，cglib 生成的子类会继承父类属性，但是 spring 创建bean 的过程中
	 *
	 * 某个需要代理的 bean 的private 属性是通过autowired 注入的， 在后置处理前已经注入完毕了
	 *
	 * 经过后置处理器时，生成了 它的子类对象（子类对象通过构造生成）
	 * 子类对象继承了属性和方法，但属性是没有赋值的 （ 如果构造中赋值了，那么子类还是有值的）
	 *
	 * 此时，我们的字段属性用 autowire 赋值的，不会自动传递给子类
	 *
	 *
	 * 调用代理对象的方法时，通过 MethodProxy.invokeSuper(proxy,args) 来调用父类的方法，父类方法访问自己的私有属性 ，属性为空 ，则空指针
	 *
	 *
	 * 所以 要么保存一下 父类的 实际对象 targetObject ，通过  MethodProxy.invoke(targetObject,args)  调用父类方法，传递真实的父类对象给他
	 *
	 * 要么 通过  Method.invoke(targetObject,args)  直接调用父类方法
	 *
	 */
}
